import { defineComponent, h, watchEffect, ref, inject, computed, nextTick } from 'vue'
import { nanoid } from 'nanoid'
import type { PropType, Ref } from 'vue'
import type { showParamsState, questionSideListState, dyFormOptionsState } from '@/types/baseConfig'
import type { addParamState } from '@/types/form'
import type { FormValidationError } from 'naive-ui'
import { getOptions } from '@/utils/dyForm'
import triggerEnum from '@/enum/triggerEnum'
import dataTypeEnum from '@/enum/dataTypeEnum'
import { getWayName, getWayOptins } from '@/enum/wayEnum'
import {
  NButton,
  NCollapseItem,
  NForm,
  NFormItem,
  NInput,
  NDataTable,
  NDrawer,
  NDrawerContent,
  NSelect,
  NDynamicTags,
  NInputNumber,
  NSwitch,
  NDropdown
} from 'naive-ui'
import type { FormInst, DataTableColumns } from 'naive-ui'
import MessageBox from '@/components/nComponents/MessageBox'

const AddParams = defineComponent({
  emits: ['save'],
  setup(props, { emit, expose }) {
    const questions = inject('questions') as Ref<questionSideListState[]>
    const options = computed(() => {
      return getOptions(questions.value)
    })
    const formRef = ref<FormInst | null>(null)
    const queryForm = ref<addParamState>({
      labelKey: '',
      way: 'noeqEmpty',
      dataType: 'string',
      trigger: ['add', 'edit'],
      value: ''
    })
    const rules = {
      labelKey: {
        required: true,
        message: '请输入字段key',
        trigger: ['input']
      },
      trigger: {
        required: true,
        message: '请选择触发时机',
        trigger: ['input']
      },
      value: {
        required: true,
        message: '请输入值',
        trigger: ['input']
      }
    }
    const handSave = () => {
      formRef.value?.validate(errors => {
        if (errors) {
          return
        }
        emit('save', queryForm.value)
        close()
      })
    }

    const handleUpdateValue = (e: string) => {
      const opitem = options.value.find((el: dyFormOptionsState) => {
        return el.labelKey === e
      })
      if (opitem) {
        queryForm.value.dataType = opitem.dataType
      } else {
        queryForm.value.dataType = 'string'
      }
    }

    const wayChange = (
      e: 'noeqEmpty' | 'eq' | 'noeq' | 'gt' | 'lt' | 'includes' | 'noincludes'
    ) => {
      queryForm.value.way = e
      setDefaultValue()
    }
    const setDefaultValue = () => {
      if (['includes', 'noincludes'].includes(queryForm.value.way)) {
        queryForm.value.value = []
      } else if (queryForm.value.dataType === 'number') {
        queryForm.value.value = 0
      } else if (queryForm.value.dataType === 'boolean') {
        queryForm.value.value = false
      } else {
        queryForm.value.value = ''
      }
    }
    const wayOptions = computed(() => {
      return getWayOptins(queryForm.value.dataType)
    })
    const show = ref(false)
    const title = ref('添加展示条件')
    const close = () => {
      show.value = false
    }
    const open = (e?: addParamState) => {
      if (e) {
        title.value = '编辑展示条件'
        queryForm.value = e
      } else {
        title.value = '添加展示条件'
        queryForm.value = {
          labelKey: '',
          way: 'noeqEmpty',
          dataType: 'string',
          trigger: ['add', 'edit'],
          value: ''
        }
      }
      show.value = true
    }

    expose({
      open
    })
    return () => (
      <>
        <NDrawer v-model:show={show.value} width={400}>
          <NDrawerContent title={title.value}>
            <NForm ref={formRef} model={queryForm.value} rules={rules}>
              <NFormItem label="字段" path="labelKey">
                <NSelect
                  v-model:value={queryForm.value.labelKey}
                  options={options.value}
                  filterable
                  label-field="labelName"
                  placeholder="请输入字段"
                  tag
                  value-field="labelKey"
                  onUpdateValue={handleUpdateValue}
                />
              </NFormItem>
              <NFormItem label="触发时机">
                <NSelect
                  multiple
                  v-model:value={queryForm.value.trigger}
                  options={triggerEnum}
                  placeholder="请选择"
                />
              </NFormItem>
              <NFormItem label="数据类型" path="dataType">
                <NSelect
                  v-model:value={queryForm.value.dataType}
                  options={dataTypeEnum}
                  placeholder="请选择"
                  onUpdateValue={setDefaultValue}
                />
              </NFormItem>
              <NFormItem label="判断条件" path="way">
                <NSelect
                  v-model:value={queryForm.value.way}
                  options={wayOptions.value}
                  placeholder="请选择"
                  onUpdateValue={wayChange}
                />
              </NFormItem>
              {queryForm.value.way && queryForm.value.way !== 'noeqEmpty' && (
                <NFormItem label="值" path="value">
                  {['includes', 'noincludes'].includes(queryForm.value.way) &&
                  ['number', 'string'].includes(queryForm.value.dataType) ? (
                    <NDynamicTags v-model:value={queryForm.value.value} />
                  ) : queryForm.value.dataType === 'number' ? (
                    <NInputNumber
                      class="w-full"
                      v-model:value={queryForm.value.value}
                      clearable
                      placeholder="请输入值"
                    />
                  ) : queryForm.value.dataType === 'boolean' ? (
                    <NSwitch v-model:value={queryForm.value.value} />
                  ) : (
                    <NInput v-model:value={queryForm.value.value} placeholder="请输入值" />
                  )}
                </NFormItem>
              )}
              <NFormItem>
                <div class="w-full flex justify-end">
                  <NButton type="primary" onClick={handSave}>
                    保存
                  </NButton>
                </div>
              </NFormItem>
            </NForm>
          </NDrawerContent>
        </NDrawer>
      </>
    )
  }
})
const ShowTable = defineComponent({
  props: {
    modelValue: {
      type: Array as PropType<addParamState[]>,
      default: () => []
    }
  },
  emits: ['update:modelValue', 'edit', 'del'],
  setup(props, { emit }) {
    const $clone = inject('$clone') as <T>(data: T) => T
    const questions = inject('questions') as Ref<questionSideListState[]>
    const x = ref(0)
    const y = ref(0)
    const rowProps = (rowData: addParamState, rowIndex: number) => {
      return {
        onContextmenu: (e: MouseEvent) => {
          oldIndex = rowIndex
          e.preventDefault()
          showDropdown.value = false
          nextTick(() => {
            showDropdown.value = true
            x.value = e.clientX
            y.value = e.clientY
          })
        }
      }
    }
    const showDropdown = ref(false)
    const options = [
      {
        label: '编辑',
        key: 'edit'
      },
      {
        label: () => h('span', { style: { color: 'red' } }, '删除'),
        key: 'delete'
      }
    ]
    const handleSelect = (e: string) => {
      const rowInfo = props.modelValue[oldIndex]
      if (e === 'edit') {
        addRef.value.open($clone(rowInfo))
      } else if (e === 'delete') {
        const list = props.modelValue
        list.splice(oldIndex, 1)
      }
      showDropdown.value = false
    }
    const getName = (key: string) => {
      let name = ''
      try {
        const getChilder = (arr: questionSideListState[]) => {
          arr.forEach((el: questionSideListState) => {
            if (el.commonForm.labelKey === key) {
              throw new Error(el.commonForm.labelName)
            }
            if (el?.RowLayoutForm) {
              if (el.RowLayoutForm.childer && el.RowLayoutForm.childer.length > 0) {
                getChilder(el.RowLayoutForm.childer)
              }
            }
          })
        }
        questions.value.forEach((el: questionSideListState) => {
          if (el.commonForm.labelKey === key) {
            throw new Error(el.commonForm.labelName)
          }
          if (el?.RowLayoutForm) {
            if (el.RowLayoutForm.childer && el.RowLayoutForm.childer.length > 0) {
              getChilder(el.RowLayoutForm.childer)
            }
          }
        })
      } catch (e) {
        name = (e as Error).message
      }
      return name || key
    }
    const columns: DataTableColumns = [
      {
        title: 'Key',
        key: 'labelKey',
        width: 80,
        ellipsis: true,
        render(row: any) {
          return [
            h(
              'span',
              {},
              {
                default: () => getName(row.labelKey)
              }
            )
          ]
        }
      },
      {
        title: '判断条件',
        key: 'way',
        render(row: any) {
          return [
            h(
              'span',
              {},
              {
                default: () => getWayName(row.way)
              }
            )
          ]
        }
      },
      {
        title: '值',
        key: 'value',
        render(row: any) {
          return [
            h(
              'span',
              {},
              {
                default: () => row.value
              }
            )
          ]
        }
      }
    ]
    const addRef = ref()
    let oldIndex = -1
    const handAddParams = (index: number) => {
      oldIndex = index
      const row: addParamState = props.modelValue[index]
      addRef.value.open(row || null)
    }
    const paramsSave = (e: addParamState) => {
      const list = props.modelValue
      if (oldIndex === -1) {
        list.push(e)
      } else {
        list[oldIndex] = e
      }
      emit('update:modelValue', list)
    }
    return () => (
      <>
        <NDataTable columns={columns} data={props.modelValue} rowProps={rowProps} />
        <div class="mt-[10px] flex justify-end">
          <NButton round onClick={() => handAddParams(-1)}>
            新增
          </NButton>
          <NButton
            style={{ marginLeft: '5px' }}
            type="warning"
            round
            onClick={() => {
              emit('edit')
            }}
          >
            编辑
          </NButton>
          <NButton
            style={{ marginLeft: '5px' }}
            class="ml-[10px]"
            type="error"
            round
            onClick={() => {
              emit('del')
            }}
          >
            删除
          </NButton>
        </div>
        <NDropdown
          placement="bottom-start"
          trigger="manual"
          x={x.value}
          y={y.value}
          options={options}
          show={showDropdown.value}
          onSelect={handleSelect}
        />
        <AddParams ref={addRef} onSave={paramsSave} />
      </>
    )
  }
})
export default defineComponent({
  props: {
    modelValue: {
      type: Array as PropType<showParamsState[]>,
      default: () => []
    }
  },
  emits: ['update:modelValue', 'setNull', 'setting'],
  setup(props, { emit }) {
    const showParams = ref<showParamsState[]>([])
    watchEffect(() => {
      if (props.modelValue) {
        showParams.value = props.modelValue
      }
    })

    /**
     *  变化回调
     * */
    const handOptions = () => {
      emit('update:modelValue', showParams.value)
    }

    /**
     *  展示条件
     * */
    const $clone = inject('$clone') as <T>(data: T) => T
    const addShow = ref(false)
    const messageBoxTitle = ref('添加条件')
    const formRef = ref<FormInst | null>(null)
    const formValue = ref<showParamsState>({
      uid: '',
      name: '',
      childer: []
    })
    const rules = {
      name: {
        required: true,
        message: '请输入备注',
        trigger: 'blur'
      }
    }
    const handAddZu = (e?: showParamsState) => {
      if (e) {
        messageBoxTitle.value = '编辑条件'
        formValue.value = $clone(e)
      } else {
        messageBoxTitle.value = '添加条件'
        formValue.value = {
          uid: '',
          name: '',
          childer: []
        }
      }
      addShow.value = true
    }
    const handDel = (index: number) => {
      showParams.value.splice(index, 1)
      handOptions()
    }
    const handSave = () => {
      formRef.value?.validate((errors?: Array<FormValidationError>) => {
        if (!errors) {
          if (formValue.value.uid) {
            const index = showParams.value.findIndex(
              (el: showParamsState) => el.uid === formValue.value.uid
            )
            if (index >= 0) {
              showParams.value[index] = formValue.value
            }
          } else {
            showParams.value.push({
              name: formValue.value.name,
              uid: nanoid(),
              childer: []
            })
          }
          emit('update:modelValue', showParams.value)
          addShow.value = false
        }
      })
    }

    const commonHeader = (title: string) => (
      <div class="cell flex items-center">
        <div class="title u-line-1">{title}</div>
      </div>
    )
    return () => (
      <>
        {showParams.value.map((item: showParamsState, index: number) => (
          <>
            <NCollapseItem
              key={item.uid}
              name={item.uid}
              v-slots={{
                header: () => h(commonHeader(item.name)),
                default: () => (
                  <ShowTable
                    v-model={item.childer}
                    onEdit={() => handAddZu(item)}
                    onDel={() => handDel(index)}
                    onUpdate:modelValue={handOptions}
                  />
                )
              }}
            />
          </>
        ))}
        <div class="mt-[20px] ml-[10px] mr-[10px]">
          <NButton class="w-full" onClick={() => handAddZu()}>
            新增条件
          </NButton>
        </div>
        <MessageBox v-model={addShow.value} title={messageBoxTitle.value} is-close>
          <NForm ref={formRef} label-width={80} model={formValue.value} rules={rules}>
            <NFormItem label="备注" path="name">
              <NInput v-model:value={formValue.value.name} placeholder="请输入备注" />
            </NFormItem>
            <div class="btns flex items-center justify-end">
              <NButton
                onClick={() => {
                  addShow.value = false
                }}
              >
                取消
              </NButton>
              <NButton class="ml10" type="primary" onClick={handSave}>
                提 交
              </NButton>
            </div>
          </NForm>
        </MessageBox>
      </>
    )
  }
})
